package com.orion.config;

import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * @author Administrator
 */
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class EsConfig {

    private static final char SEPARATE = ':';

    private List<String> cluster;
    private String username;
    private String password;

    public void setCluster(List<String> cluster) {
        this.cluster = cluster;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    @Bean
    public RestClientBuilder builder() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

        HttpHost[] httpHosts = new HttpHost[cluster.size()];
        for (int i = 0; i < cluster.size(); i++) {
            List<String> temp = StrUtil.split(cluster.get(i), SEPARATE);
            String ip = temp.get(0);
            int port = Integer.parseInt(temp.get(1));
            httpHosts[i] = new HttpHost(ip, port);
        }
        return RestClient.builder(httpHosts).setHttpClientConfigCallback(
                httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
    }

    /**
     * 低级客户端
     * <p>
     * 低级客户端的功能包括：
     * <p>
     * 最小依赖
     * 跨所有可用节点的负载平衡
     * 在节点故障和特定响应代码的情况下进行故障转移
     * 失败的连接惩罚（是否重试失败的节点取决于它连续失败的次数；失败的尝试越多，客户端在再次尝试同一节点之前等待的时间越长）
     * 持久连接
     * 跟踪请求和响应的日志记录
     * 集群节点的可选自动发现
     *
     * @return
     */
    @Bean("lowClient")
    public RestClient lowClient(RestClientBuilder builder) {
        return builder.build();
    }

    /**
     * 使用 Jackson 映射器创建传输
     */
    @Bean("transport")
    public ElasticsearchTransport transport(RestClient lowClient, ObjectMapper objectMapper) {
        return new RestClientTransport(lowClient, new JacksonJsonpMapper(objectMapper));
    }

    @Bean("highClient")
    public RestHighLevelClient restHighLevelClient(RestClientBuilder builder,ElasticsearchClient  client){
        return new RestHighLevelClient(builder);
    }

    /**
     * 创建 API 客户端
     */
    @Bean("esClient")
    public ElasticsearchClient esClient(ElasticsearchTransport transport) {
        return new ElasticsearchClient(transport);
    }
}
